package com.ruoyi.trainingManagement.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.teacher.service.IteacherService;
import com.ruoyi.trainingManagement.domain.ClassScheduleDetailed;
import com.ruoyi.trainingManagement.domain.Vo.CourseAndTimeVo;
import com.ruoyi.trainingManagement.mapper.ClassScheduleDetailedMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.trainingManagement.mapper.CourseScheduleDetailsMapper;
import com.ruoyi.trainingManagement.domain.CourseScheduleDetails;
import com.ruoyi.trainingManagement.service.ICourseScheduleDetailsService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 课程排课详细信息Service业务层处理
 *
 * @author chenxl
 * @date 2025-06-18
 */
@Service
public class CourseScheduleDetailsServiceImpl implements ICourseScheduleDetailsService
{
    private static final Logger log = LoggerFactory.getLogger(CourseScheduleDetailsServiceImpl.class);

    @Autowired
    private CourseScheduleDetailsMapper courseScheduleDetailsMapper;
    @Autowired
    private IteacherService teacherService;
    @Autowired
    private ClassScheduleDetailedServiceImpl classScheduleDetailedService;
    @Autowired
    private ClassScheduleDetailedMapper classScheduleDetailedMapper;


    // 遗传算法常量
    private static final String UN_FIXED_TIME = "unFixedTime";
    private static final String IS_FIX_TIME = "fixedTime";
    // 新增：时间常量（每周7天，每天20节课）
    private static final int DAYS_PER_WEEK = 7;
    private static final int SLOTS_PER_DAY = 20;
    // 新增：预加载缓存（课程班ID → 行政班ID列表）
    private Map<String, List<String>> courseToAdminClassesMap;

    // 遗传算法参数
    private static final int POPULATION_SIZE = 200;
    private static final int GENERATION_COUNT = 100; // 迭代代数
    private static final double CROSSOVER_RATE = 0.8; // 交叉率
    private static final double MUTATION_RATE = 0.1; // 变异率
    private static final double ELITISM_RATE = 0.1; // 精英保留率

    // 基因长度相关常量
    private static final int GENE_LENGTH = 54; // 总基因长度40(固定)+5(时间)+8(教室)
    private static final int FIXED_PART_LENGTH = 40; // 固定部分长度
    private static final int TIME_PART_START = 40; // 时间部分起始位置
    private static final int TIME_PART_LENGTH = 5; // 时间部分长度
    private static final int CLASSROOM_PART_START = 45; // 教室部分起始位置
    private static final int CLASSROOM_PART_LENGTH = 8; // 教室部分长度

    /**
     * 查询课程排课详细信息
     *
     * @param id 课程排课详细信息主键
     * @return 课程排课详细信息
     */
    @Override
    public CourseScheduleDetails selectCourseScheduleDetailsById(String id)
    {
        return courseScheduleDetailsMapper.selectCourseScheduleDetailsById(id);
    }

    /**
     * 查询课程排课详细信息列表
     *
     * @param courseScheduleDetails 课程排课详细信息
     * @return 课程排课详细信息
     */
    @Override
    public List<CourseScheduleDetails> selectCourseScheduleDetailsList(CourseScheduleDetails courseScheduleDetails)
    {
        return courseScheduleDetailsMapper.selectCourseScheduleDetailsList(courseScheduleDetails);
    }

    /**
     * 新增课程排课详细信息
     *
     * @param courseScheduleDetails 课程排课详细信息
     * @return 结果
     */
    @Override
    public int insertCourseScheduleDetails(CourseScheduleDetails courseScheduleDetails)
    {
        return courseScheduleDetailsMapper.insertCourseScheduleDetails(courseScheduleDetails);
    }
    /**
     * 修改课程排课详细信息
     *
     * @param courseScheduleDetails 课程排课详细信息
     * @return 结果
     */
    @Override
    public int updateCourseScheduleDetails(CourseScheduleDetails courseScheduleDetails)
    {
        return courseScheduleDetailsMapper.updateCourseScheduleDetails(courseScheduleDetails);
    }

    /**
     * 批量删除课程排课详细信息
     *
     * @param ids 需要删除的课程排课详细信息主键
     * @return 结果
     */
    @Override
    public int deleteCourseScheduleDetailsByIds(String[] ids)
    {
        return courseScheduleDetailsMapper.deleteCourseScheduleDetailsByIds(ids);
    }

    /**
     * 删除课程排课详细信息信息
     *
     * @param id 课程排课详细信息主键
     * @return 结果
     */
    @Override
    public int deleteCourseScheduleDetailsById(String id)
    {
        return courseScheduleDetailsMapper.deleteCourseScheduleDetailsById(id);
    }

    @Override
    public int updateTeacherIdById(String id, String teacherId) {
        System.out.println("课程ID：" + id + "教师ID：" + teacherId);
        return courseScheduleDetailsMapper.updateTeacherIdById(id, teacherId);
    }

    @Override
    public List<CourseScheduleDetails> selectByCourseSemesterGrade(String courseId, int semesterId, int grade) {
        return courseScheduleDetailsMapper.selectByCourseSemesterGrade(courseId, semesterId, grade);
    }

    /**
     * 使用遗传算法进行自动排课
     *
     * @param semesterId 学期ID
     * @return 排课结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult autoCourseScheduling(int semesterId, int academicYear, int isScheduleCompleted) {
        System.out.println("\n===== 开始自动排课流程 =====");
        System.out.println("参数: 学期ID=" + semesterId + ", 学年=" + academicYear + ", 排课状态=" + isScheduleCompleted);

        // 1. 查询待排课课程
        long startTime = System.currentTimeMillis();
        List<CourseScheduleDetails> courseScheduleDetailsList = courseScheduleDetailsMapper.findCoursesBySemesterAndYearAndStatus(
                semesterId,
                academicYear,
                isScheduleCompleted
        );
        long endTime = System.currentTimeMillis();
        System.out.println("1. 查询待排课课程完成，耗时: " + (endTime - startTime) + "ms");
        System.out.println("待排课的班级个数：" + courseScheduleDetailsList.size());

        // 打印前10条课程信息用于调试
        if (!courseScheduleDetailsList.isEmpty()) {
            System.out.println("前10条待排课课程信息:");
            for (int i = 0; i < Math.min(10, courseScheduleDetailsList.size()); i++) {
                CourseScheduleDetails course = courseScheduleDetailsList.get(i);
                System.out.printf("  [%d] 课程班ID: %s, 课程ID: %s, 教师ID: %s, 周频次: %d, 单次节数: %d\n",
                        i+1,
                        course.getId(),
                        course.getCourseId(),
                        course.getTeacherId(),
                        course.getWeekType() != null ? course.getWeekType() : 0,
                        course.getLessonCount() != null ? course.getLessonCount() : 0);
            }
        }

        // 根据lesson_count、week_type创建class_schedule_details对应的记录
        System.out.println("\n2. 创建课程详细安排记录...");
        int totalClassScheduleRecords = 0;
        for (CourseScheduleDetails courseScheduleDetails : courseScheduleDetailsList) {
            int weekType = courseScheduleDetails.getWeekType() != null ? courseScheduleDetails.getWeekType() : 0;
            String coursePeriod = courseScheduleDetails.getCoursePeriod();

            // 安全处理空值
            String periodStr = (coursePeriod != null) ? coursePeriod.toString() : "";

            // 预计算长度和最后一个字符值
            int periodLength = periodStr.length();
            long lastCharValue = 0L;
            if (periodLength > 0) {
                char lastChar = periodStr.charAt(periodLength - 1);
                lastCharValue = Character.isDigit(lastChar)
                        ? Character.getNumericValue(lastChar)
                        : 0L;
            }

            for (int i = 1; i <= weekType; i++) {
                ClassScheduleDetailed classScheduleDetailed = new ClassScheduleDetailed();
                classScheduleDetailed.setId(IdUtils.fastSimpleUUID());
                classScheduleDetailed.setCourseScheduleDetailsId(courseScheduleDetails.getId());
                classScheduleDetailed.setLessonCount(Long.valueOf(courseScheduleDetails.getLessonCount() != null ? courseScheduleDetails.getLessonCount() : 0));
                long weekTypeValue;
                int index = i - 1;
                if (index < periodLength) {
                    char weekTypeChar = periodStr.charAt(index);
                    weekTypeValue = Character.isDigit(weekTypeChar)
                            ? Character.getNumericValue(weekTypeChar)
                            : 0L;
                } else {
                    weekTypeValue = lastCharValue;
                }
                classScheduleDetailed.setWeekType(weekTypeValue);
                classScheduleDetailedService.insertClassScheduleDetailed(classScheduleDetailed);
                totalClassScheduleRecords++;
            }
        }
        System.out.println("创建完成，共生成 " + totalClassScheduleRecords + " 条课程详细安排记录");

        if (CollectionUtils.isEmpty(courseScheduleDetailsList)) {
            return AjaxResult.error("排课失败，查询不到待排课的班级！");
        }

        // 2. 预加载：课程班→行政班映射
        System.out.println("\n3. 预加载课程班→行政班映射...");
        startTime = System.currentTimeMillis();
        preloadCourseToAdminClasses(courseScheduleDetailsList);
        endTime = System.currentTimeMillis();
        System.out.println("预加载完成，耗时: " + (endTime - startTime) + "ms");
        System.out.println("共加载 " + courseToAdminClassesMap.size() + " 个课程班的行政班映射关系");

        // 打印前5个课程班的行政班映射用于调试
        if (!courseToAdminClassesMap.isEmpty()) {
            System.out.println("前5个课程班的行政班映射:");
            int count = 0;
            for (Map.Entry<String, List<String>> entry : courseToAdminClassesMap.entrySet()) {
                if (count >= 5) break;
                System.out.printf("  课程班ID: %s, 行政班ID列表: %s\n",
                        entry.getKey(),
                        entry.getValue().toString());
                count++;
            }
        }

        // 3. 将课程信息编码为基因
        System.out.println("\n4. 将课程信息编码为基因...");
        startTime = System.currentTimeMillis();
        Map<String, List<String>> geneMap = coding(courseScheduleDetailsList);
        endTime = System.currentTimeMillis();
        System.out.println("基因编码完成，耗时: " + (endTime - startTime) + "ms");

        List<String> baseGenes = geneMap.get(UN_FIXED_TIME);
        System.out.println("基础基因模板数量: " + baseGenes.size());

        // 打印前3个基因样本
        if (!baseGenes.isEmpty()) {
            System.out.println("前3个基础基因样本:");
            for (int i = 0; i < Math.min(3, baseGenes.size()); i++) {
                System.out.printf("  [%d] 基因长度: %d, 内容: %s\n",
                        i+1,
                        baseGenes.get(i).length(),
                        baseGenes.get(i));
            }
        }

        // 4. 生成初始种群
        System.out.println("\n5. 生成初始种群...");
        startTime = System.currentTimeMillis();
        List<List<String>> population = new ArrayList<>(POPULATION_SIZE);
        for (int i = 0; i < POPULATION_SIZE; i++) {
            List<String> individual = generateRandomIndividual(baseGenes);
            population.add(individual);

            // 每20个个体打印一次进度
            if ((i + 1) % 20 == 0 || i == 0 || i == POPULATION_SIZE - 1) {
                System.out.printf("  已生成个体 #%d | 基因数: %d\n", i+1, individual.size());
            }
        }
        endTime = System.currentTimeMillis();
        System.out.println("初始种群生成完成，耗时: " + (endTime - startTime) + "ms");

        // 5. 遗传算法核心迭代
        System.out.println("\n6. 遗传算法核心迭代...");
        startTime = System.currentTimeMillis();
        population = geneticAlgorithmIteration(population);
        endTime = System.currentTimeMillis();
        System.out.println("遗传算法迭代完成，耗时: " + (endTime - startTime) + "ms");

        // 6. 评估最终种群并选择最优个体
        System.out.println("\n7. 评估最终种群并选择最优个体...");
        List<IndividualFitness> fitnessList = evaluatePopulationFitness(population);
        Optional<IndividualFitness> bestFitnessOpt = fitnessList.stream()
                .min(Comparator.comparingInt(IndividualFitness::getConflictCount));

        if (!bestFitnessOpt.isPresent()) {
            return AjaxResult.error("排课失败，未能找到可行的排课方案！");
        }

        IndividualFitness bestFitness = bestFitnessOpt.get();
        List<String> bestIndividual = bestFitness.getIndividual();
        int minConflict = bestFitness.getConflictCount();

        System.out.println("最优个体冲突数: " + minConflict);

        // 7. 保存最优排课方案到数据库
        System.out.println("\n8. 保存最优排课方案到数据库...");
        //saveBestSchedule(bestIndividual, semesterId, academicYear);

        System.out.println("\n===== 自动排课流程结束 =====");
        return AjaxResult.success("排课成功，最优方案冲突数：" + minConflict);
    }
    /**
     * 遗传算法核心迭代逻辑
     */
    private List<List<String>> geneticAlgorithmIteration(List<List<String>> population) {
        for (int generation = 1; generation <= GENERATION_COUNT; generation++) {
            long startTime = System.currentTimeMillis();

            // 评估种群适应度
            List<IndividualFitness> fitnessList = evaluatePopulationFitness(population);

            // 记录当前代的最优解
            int currentMinConflict = fitnessList.stream()
                    .mapToInt(IndividualFitness::getConflictCount)
                    .min()
                    .orElse(Integer.MAX_VALUE);

            // 精英保留
            int eliteCount = (int) (POPULATION_SIZE * ELITISM_RATE);
            List<List<String>> newPopulation = new ArrayList<>(eliteCount);

            // 按冲突数排序，保留精英个体
            fitnessList.sort(Comparator.comparingInt(IndividualFitness::getConflictCount));
            for (int i = 0; i < eliteCount; i++) {
                newPopulation.add(fitnessList.get(i).getIndividual());
            }

            // 选择、交叉和变异操作
            Random random = new Random();
            while (newPopulation.size() < POPULATION_SIZE) {
                // 锦标赛选择父代
                List<String> parent1 = tournamentSelection(fitnessList);
                List<String> parent2 = tournamentSelection(fitnessList);

                List<String> child;
                // 交叉操作
                if (random.nextDouble() < CROSSOVER_RATE) {
                    child = crossover(parent1, parent2);
                } else {
                    child = new ArrayList<>(parent1); // 不交叉，直接复制父代
                }

                // 变异操作
                if (random.nextDouble() < MUTATION_RATE) {
                    child = mutate(child);
                }

                newPopulation.add(child);
            }

            // 更新种群
            population = newPopulation;

            long endTime = System.currentTimeMillis();
            System.out.printf("第 %d 代进化完成，耗时: %dms，最优冲突数: %d\n",
                    generation, (endTime - startTime), currentMinConflict);
        }

        return population;
    }

    /**
     * 锦标赛选择方法
     */
    private List<String> tournamentSelection(List<IndividualFitness> fitnessList) {
        Random random = new Random();
        int tournamentSize = 3; // 锦标赛规模
        List<IndividualFitness> tournament = new ArrayList<>(tournamentSize);

        // 随机选择个体参加锦标赛
        for (int i = 0; i < tournamentSize; i++) {
            int randomIndex = random.nextInt(fitnessList.size());
            tournament.add(fitnessList.get(randomIndex));
        }

        // 返回冲突数最小的个体
        return tournament.stream()
                .min(Comparator.comparingInt(IndividualFitness::getConflictCount))
                .map(IndividualFitness::getIndividual)
                .orElse(fitnessList.get(0).getIndividual());
    }

    /**
     * 交叉操作 - 单点交叉
     */
    private List<String> crossover(List<String> parent1, List<String> parent2) {
        Random random = new Random();
        List<String> child = new ArrayList<>(parent1.size());

        // 确保两个父代长度相同
        if (parent1.size() != parent2.size()) {
            return new ArrayList<>(parent1); // 长度不同时直接返回第一个父代
        }

        // 随机选择交叉点
        int crossoverPoint = random.nextInt(parent1.size());

        // 执行交叉
        for (int i = 0; i < parent1.size(); i++) {
            if (i < crossoverPoint) {
                child.add(parent1.get(i));
            } else {
                child.add(parent2.get(i));
            }
        }

        return child;
    }

    /**
     * 变异操作 - 随机改变时间部分
     */
    private List<String> mutate(List<String> individual) {
        Random random = new Random();
        List<String> mutatedIndividual = new ArrayList<>(individual);

        // 随机选择一个基因进行变异
        int geneIndex = random.nextInt(individual.size());
        String gene = individual.get(geneIndex);

        // 解析基因中的关键信息
        GeneInfo geneInfo = parseGene(gene);
        if (geneInfo == null) {
            return mutatedIndividual;
        }

        // 生成新的随机时间
        int dayOfWeek = random.nextInt(7) + 1; // 周几（1-7）

        // 开始节次（奇数01-19）
        int startSlot;
        do {
            startSlot = 1 + random.nextInt(10) * 2;
        } while (startSlot + geneInfo.endSlot - geneInfo.startSlot > 20);

        // 结束节次
        int endSlot = startSlot + (geneInfo.endSlot - geneInfo.startSlot);
        String timePart = String.format("%d%02d%02d", dayOfWeek, startSlot, endSlot);

        // 替换基因中的时间部分
        String fixedPart = gene.substring(0, TIME_PART_START);
        String classroomPart = gene.substring(CLASSROOM_PART_START);
        String mutatedGene = fixedPart + timePart + classroomPart;

        // 更新个体
        mutatedIndividual.set(geneIndex, mutatedGene);

        return mutatedIndividual;
    }

    /**
     * 保存最优排课方案到数据库
     */
//    private void saveBestSchedule(List<String> bestIndividual, int semesterId, int academicYear) {
//        // 清空当前学期已有的排课结果
//        courseScheduleDetailsMapper.deleteScheduleBySemester(semesterId, academicYear);
//
//        // 保存最优方案
//        for (String gene : bestIndividual) {
//            GeneInfo geneInfo = parseGene(gene);
//            if (geneInfo == null) {
//                continue;
//            }
//
//            // 解析固定部分获取课程班ID
//            String courseScheduleDetailsId = gene.substring(0, 8);
//
//            // 更新课程排课详细信息
//            CourseScheduleDetails courseScheduleDetails = new CourseScheduleDetails();
//            courseScheduleDetails.setId(courseScheduleDetailsId);
//            courseScheduleDetails.setDayOfWeek(geneInfo.dayOfWeek + 1); // 转换为1-7
//            courseScheduleDetails.setStartSlot(geneInfo.startSlot + 1); // 转换为1-20
//            courseScheduleDetails.setEndSlot(geneInfo.endSlot + 1); // 转换为1-20
//            courseScheduleDetails.setClassroomId(geneInfo.classroomId);
//
//            courseScheduleDetailsMapper.updateScheduleTimeAndClassroom(courseScheduleDetails);
//        }
//    }
    /**
     * 批量预加载：课程班ID → 行政班ID列表
     */
    private void preloadCourseToAdminClasses(List<CourseScheduleDetails> courseList) {
        if (CollectionUtils.isEmpty(courseList)) {
            return;
        }

        // 提取所有课程班ID
        List<String> courseIds = courseList.stream()
                .map(CourseScheduleDetails::getId)
                .collect(Collectors.toList());

        // 批量查询行政班信息
        List<Map<String, Object>> courseAdminClassRelations =
                courseScheduleDetailsMapper.selectAdminClassIdsByCourseIds(courseIds);

        // 构建映射关系
        courseToAdminClassesMap = courseAdminClassRelations.stream()
                .collect(Collectors.groupingBy(
                        map -> (String) map.get("courseId"),
                        Collectors.mapping(map -> (String) map.get("adminClassId"), Collectors.toList())
                ));
    }


    /**
     * 评估种群中每个个体的适应度（核心：冲突检测）
     */
    private List<IndividualFitness> evaluatePopulationFitness(List<List<String>> population) {
        System.out.println("开始评估 " + population.size() + " 个个体的适应度...");
        List<IndividualFitness> fitnessList = new ArrayList<>();

        int processedCount = 0;
        for (List<String> individual : population) {
            // 计算该个体的冲突数
            int conflictCount = checkIndividualConflict(individual);
            fitnessList.add(new IndividualFitness(individual, conflictCount));

            // 每50个个体打印一次进度
            if ((++processedCount) % 50 == 0 || processedCount == population.size()) {
                System.out.printf("  已评估 %d/%d 个个体\n", processedCount, population.size());
            }
        }

        return fitnessList;
    }
    /**
     * 检测单个个体（排课方案）的冲突
     * 步骤：初始化教师/教室/行政班课表 → 逐个课程写入并检测冲突
     */
    private int checkIndividualConflict(List<String> individual) {
        // 1. 初始化课表：教师ID → 7天×20节课的BitSet
        Map<String, BitSet[]> teacherSchedules = new HashMap<>();
        // 2. 教室ID → 7天×20节课的BitSet
        Map<String, BitSet[]> classroomSchedules = new HashMap<>();
        // 3. 行政班ID → 7天×20节课的BitSet
        Map<String, BitSet[]> adminClassSchedules = new HashMap<>();

        int totalConflicts = 0; // 总冲突数
        int geneCount = 0;
        int teacherConflictCount = 0;
        int classroomConflictCount = 0;
        int adminClassConflictCount = 0;

        for (String gene : individual) {
            geneCount++;
            // 解析基因中的关键信息
            GeneInfo geneInfo = parseGene(gene);
            if (geneInfo == null) {
                System.out.printf("  基因解析失败 (基因 #%d): %s\n", geneCount, gene);
                totalConflicts++; // 基因解析失败视为冲突
                continue;
            }

            // 2. 检测并记录冲突
            boolean hasConflict = false;

            // 2.1 教师冲突
            if (checkAndMarkTeacherConflict(teacherSchedules, geneInfo)) {
                totalConflicts++;
                teacherConflictCount++;
                hasConflict = true;
                System.out.printf("  教师冲突 (基因 #%d): 教师ID=%s, 时间=周%d 第%d-%d节\n",
                        geneCount,
                        geneInfo.teacherId,
                        geneInfo.dayOfWeek + 1,
                        geneInfo.startSlot + 1,
                        geneInfo.endSlot + 1);
            }

            // 2.2 教室冲突
            if (checkAndMarkClassroomConflict(classroomSchedules, geneInfo)) {
                totalConflicts++;
                classroomConflictCount++;
                hasConflict = true;
                System.out.printf("  教室冲突 (基因 #%d): 教室ID=%s, 时间=周%d 第%d-%d节\n",
                        geneCount,
                        geneInfo.classroomId,
                        geneInfo.dayOfWeek + 1,
                        geneInfo.startSlot + 1,
                        geneInfo.endSlot + 1);
            }

            // 2.3 行政班冲突
            if (checkAndMarkAdminClassConflict(adminClassSchedules, geneInfo)) {
                totalConflicts++;
                adminClassConflictCount++;
                hasConflict = true;
                System.out.printf("  行政班冲突 (基因 #%d): 行政班ID=%s, 时间=周%d 第%d-%d节\n",
                        geneCount,
                        geneInfo.adminClassIds.toString(),
                        geneInfo.dayOfWeek + 1,
                        geneInfo.startSlot + 1,
                        geneInfo.endSlot + 1);
            }

            // 每100个基因打印一次进度
            if (geneCount % 100 == 0) {
                System.out.printf("  已检测 %d/%d 个基因，当前冲突数: %d\n",
                        geneCount,
                        individual.size(),
                        totalConflicts);
            }
        }

        System.out.printf("个体冲突检测完成，总基因数: %d, 总冲突数: %d (教师:%d, 教室:%d, 行政班:%d)\n",
                geneCount,
                totalConflicts,
                teacherConflictCount,
                classroomConflictCount,
                adminClassConflictCount);

        return totalConflicts;
    }
    /**
     * 解析基因字符串，提取关键信息
     * 基因结构：固定部分(40位) + 时间(5位) + 教室(8位)
     */
    private GeneInfo parseGene(String gene) {
        try {
            // 确保基因长度正确
            if (gene.length() < GENE_LENGTH) {
                System.out.println("基因长度不足，需要40位，但实际只有" + gene.length() + "位: " + gene);

                // 补齐到所需长度
                gene = String.format("%-" + GENE_LENGTH + "s", gene).replace(' ', '0');
            } else if (gene.length() > GENE_LENGTH) {
                // 截断过长的基因
                gene = gene.substring(0, GENE_LENGTH);
            }

            // 固定部分：前40位（课程班ID在0-7位）
            String courseId = gene.substring(0, 8); // 课程班ID（8位）
            String teacherId = gene.substring(16, 24); // 教师ID（固定部分第3段，8位）
            String classroomId = gene.substring(45, 53); // 教室ID（后8位）

            // 时间部分：40-45位（5位：周几(1位)+开始节(2位)+结束节(2位)）
            String timePart = gene.substring(40, 45);
            int dayOfWeek = Integer.parseInt(timePart.substring(0, 1)) - 1; // 转换为0-6（BitSet数组索引）
            int startSlot = Integer.parseInt(timePart.substring(1, 3)) - 1; // 转换为0-19
            int endSlot = Integer.parseInt(timePart.substring(3, 5)) - 1;

            // 获取该课程班对应的行政班列表
            List<String> adminClassIds = courseToAdminClassesMap.getOrDefault(courseId, Collections.emptyList());

            return new GeneInfo(teacherId, classroomId, adminClassIds, dayOfWeek, startSlot, endSlot);
        } catch (Exception e) {
            System.out.println("基因解析失败：" + gene);
            return null;
        }
    }

    /**
     * 检测并标记教师冲突
     * 逻辑：教师在[startSlot, endSlot]区间是否已被占用
     */
    private boolean checkAndMarkTeacherConflict(Map<String, BitSet[]> teacherSchedules, GeneInfo geneInfo) {
        String teacherId = geneInfo.teacherId;
        int day = geneInfo.dayOfWeek;
        int start = geneInfo.startSlot;
        int end = geneInfo.endSlot;

        // 初始化该教师的课表（7天）
        BitSet[] weekSchedule = teacherSchedules.computeIfAbsent(teacherId, k -> initWeekSchedule());
        BitSet daySchedule = weekSchedule[day];

        // 检测区间是否有占用（[start, end]包含end，所以+1）
        boolean hasConflict = daySchedule.get(start, end + 1).cardinality() > 0;

        // 打印详细的检测信息
        if (hasConflict) {
            System.out.printf("  教师冲突检测: 教师ID=%s, 周%d 第%d-%d节, 冲突状态=%b\n",
                    teacherId,
                    day + 1,
                    start + 1,
                    end + 1,
                    hasConflict);
        }

        // 标记为占用
        if (!hasConflict) {
            daySchedule.set(start, end + 1);
        }

        return hasConflict;
    }

    /**
     * 检测并标记教室冲突
     * 逻辑：教室在[startSlot, endSlot]区间是否已被占用
     */
    private boolean checkAndMarkClassroomConflict(Map<String, BitSet[]> classroomSchedules, GeneInfo geneInfo) {
        String classroomId = geneInfo.classroomId;
        int day = geneInfo.dayOfWeek;
        int start = geneInfo.startSlot;
        int end = geneInfo.endSlot;

        // 初始化该教室的课表（7天）
        BitSet[] weekSchedule = classroomSchedules.computeIfAbsent(classroomId, k -> initWeekSchedule());
        BitSet daySchedule = weekSchedule[day];

        // 检测区间是否有占用
        boolean hasConflict = daySchedule.get(start, end + 1).cardinality() > 0;

        // 打印详细的检测信息
        if (hasConflict) {
            System.out.printf("  教室冲突检测: 教室ID=%s, 周%d 第%d-%d节, 冲突状态=%b\n",
                    classroomId,
                    day + 1,
                    start + 1,
                    end + 1,
                    hasConflict);
        }

        // 标记为占用
        if (!hasConflict) {
            daySchedule.set(start, end + 1);
        }

        return hasConflict;
    }

    /**
     * 检测并标记行政班冲突
     * 逻辑：该课程涉及的所有行政班在[startSlot, endSlot]区间是否已被占用
     */
    private boolean checkAndMarkAdminClassConflict(Map<String, BitSet[]> adminClassSchedules, GeneInfo geneInfo) {
        int day = geneInfo.dayOfWeek;
        int start = geneInfo.startSlot;
        int end = geneInfo.endSlot;

        boolean hasConflict = false;

        for (String adminClassId : geneInfo.adminClassIds) {
            // 初始化该行政班的课表（7天）
            BitSet[] weekSchedule = adminClassSchedules.computeIfAbsent(adminClassId, k -> initWeekSchedule());
            BitSet daySchedule = weekSchedule[day];

            // 检测区间是否有占用
            boolean classConflict = daySchedule.get(start, end + 1).cardinality() > 0;

            // 打印详细的检测信息
            if (classConflict) {
                System.out.printf("  行政班冲突检测: 行政班ID=%s, 周%d 第%d-%d节, 冲突状态=%b\n",
                        adminClassId,
                        day + 1,
                        start + 1,
                        end + 1,
                        classConflict);
                hasConflict = true;
            }

            // 标记为占用
            if (!classConflict) {
                daySchedule.set(start, end + 1);
            }
        }

        return hasConflict;
    }

    /**
     * 初始化一周的课表（7天，每天一个BitSet<20>）
     */
    private BitSet[] initWeekSchedule() {
        BitSet[] weekSchedule = new BitSet[DAYS_PER_WEEK];
        for (int i = 0; i < DAYS_PER_WEEK; i++) {
            weekSchedule[i] = new BitSet(SLOTS_PER_DAY); // 初始全为false（未占用）
        }
        return weekSchedule;
    }
    /**
     * 基因信息封装类（解析后的关键信息）
     */
    private static class GeneInfo {
        String teacherId; // 教师ID
        String classroomId; // 教室ID
        List<String> adminClassIds; // 涉及的行政班ID列表
        int dayOfWeek; // 周几（0-6）
        int startSlot; // 开始节（0-19）
        int endSlot; // 结束节（0-19）

        public GeneInfo(String teacherId, String classroomId, List<String> adminClassIds, int dayOfWeek, int startSlot, int endSlot) {
            this.teacherId = teacherId;
            this.classroomId = classroomId;
            this.adminClassIds = adminClassIds;
            this.dayOfWeek = dayOfWeek;
            this.startSlot = startSlot;
            this.endSlot = endSlot;
        }
    }

    /**
     * 个体适应度封装类（个体+冲突数）
     */
    private static class IndividualFitness {
        List<String> individual;
        int conflictCount;

        public IndividualFitness(List<String> individual, int conflictCount) {
            this.individual = individual;
            this.conflictCount = conflictCount;
        }

        public List<String> getIndividual() {
            return individual;
        }

        public int getConflictCount() {
            return conflictCount;
        }
    }

    /**
     * 将CourseScheduleDetails转换为遗传算法所需的基因编码
     */
    private Map<String, List<String>> coding(List<CourseScheduleDetails> courseList) {
        System.out.println("开始基因编码，共 " + courseList.size() + " 个课程...");
        Map<String, List<String>> geneMap = new HashMap<>();
        List<String> unFixedTimeGeneList = new ArrayList<>();
        List<String> fixedTimeGeneList = new ArrayList<>();

        int filteredCount = 0;
        int failedEncodingCount = 0;

        for (CourseScheduleDetails course : courseList) {
            // 过滤无教师ID的课程（无法排课）
            String teacherId = course.getTeacherId();
            if (teacherId == null || teacherId.trim().isEmpty()) {
                System.out.println("过滤课程: 课程班ID=" + course.getId() + "，原因: 未设置教师ID");
                filteredCount++;
                continue;
            }

            // 1. 构建固定字段部分（定长38位）
            String fixedPart = buildFixedGene(course);
            if (fixedPart == null) {
                System.out.println("基因构建失败: 课程班ID=" + course.getId());
                failedEncodingCount++;
                continue;
            }

            // 2. 非固定部分：时间(5位) + 教室(8位) = 13位
            String timePart = "00000";     // 5位占位符
            String classroomPart = "00000000"; // 8位占位符（1校区+2教学楼+3教室+1楼层+1类型）
            // 3. 按周频次生成对应数量的基因（每周几次课就生成几个基因）
            int weekType = course.getWeekType() != null ? course.getWeekType() : 1;
            for (int i = 0; i < weekType; i++) {
                String fullGene = fixedPart + timePart + classroomPart;
                unFixedTimeGeneList.add(fullGene);
            }
        }

        System.out.println("基因编码完成:");
        System.out.printf("  总课程数: %d, 过滤课程数: %d, 编码失败数: %d\n",
                courseList.size(),
                filteredCount,
                failedEncodingCount);
        System.out.printf("  生成未排课基因数: %d\n", unFixedTimeGeneList.size());

        geneMap.put(UN_FIXED_TIME, unFixedTimeGeneList); // 所有课程均为待排课
        return geneMap;
    }

    /**
     * 构建固定字段部分（定长38位）
     * 字段顺序及长度：
     * 1. 课程班ID（8位）
     * 2. 课程ID（8位）
     * 3. 教师ID（8位）
     * 4. 课程类型（2位）
     * 5. 教学方式（1位）
     * 6. 校区（1位）
     * 7. 周频次（1位）
     * 8. 单次节数（1位）
     * 9. 开始周（2位）
     * 10. 结束周（2位）
     * 11. 最大容量（3位）
     * 12. 排课优先级（1位）
     * 13. 学期（1位）
     * 14. 学年（2位）
     */
    private String buildFixedGene(CourseScheduleDetails course) {
        try {
            return String.join("",
                    formatId(course.getId(), 8),                 // 1. 课程班ID（8位）
                    formatId(course.getCourseId(), 8),           // 2. 课程ID（8位）
                    formatId(course.getTeacherId(), 8),          // 3. 教师ID（8位）
                    formatNumber(course.getCourseType(), 2),     // 4. 课程类型（2位）
                    formatNumber(course.getTeachingMode(), 1),   // 5. 教学方式（1位）
                    formatId(String.valueOf(course.getCampus()), 1),             // 6. 校区（1位）
                    formatNumber(course.getWeekType(), 1),       // 7. 周频次（1位）
                    formatNumber(course.getLessonCount(), 1),    // 8. 单次节数（1位）
                    formatNumber(course.getStartWeek(), 2),      // 9. 开始周（2位）
                    formatNumber(course.getEndWeek(), 2),        // 10. 结束周（2位）
                    formatNumber(course.getMaxCapacity(), 3),    // 11. 最大容量（3位）
                    formatNumber(course.getSchedulePriority(), 1), // 12. 排课优先级（1位）
                    formatNumber(course.getSemester(), 1),         // 13. 学期（1位）
                    formatAcademicYear(course.getAcademicYear())         // 14. 学年（2位）
            );
        } catch (Exception e) {
            System.out.println("课程班ID:" + course.getId() + " 固定字段构建失败：" + e.getMessage());
            return null;
        }
    }

    // 工具方法：格式化ID（截取/补零至指定长度，保留字母数字）
    private String formatId(String id, int length) {
        if (id == null) id = "";
        String cleanId = id.replaceAll("[^a-zA-Z0-9]", ""); // 移除特殊字符
        return padOrTruncate(cleanId, length);
    }

    // 工具方法：格式化数字（补零至指定长度，null则补零）
    private String formatNumber(Number num, int length) {
        String numStr = (num == null) ? "0" : String.valueOf(num);
        return padOrTruncate(numStr, length);
    }

    // 工具方法：格式化学年（取后2位，补零至2位）
    private String formatAcademicYear(Integer academicYear) {
        String yearStr = (academicYear == null) ? "0" : String.valueOf(academicYear);
        if (yearStr.length() >= 2) {
            yearStr = yearStr.substring(yearStr.length() - 2); // 取后2位（如2025→"25"）
        }
        return padOrTruncate(yearStr, 2);
    }

    // 工具方法：补零或截断至指定长度
    private String padOrTruncate(String str, int length) {
        if (str.length() >= length) {
            return str.substring(0, length);
        } else {
            return String.format("%-" + length + "s", str).replace(' ', '0');
        }
    }
    /**
     * 为每个个体生成随机的非固定部分
     */
    private List<String> generateRandomIndividual(List<String> baseGenes) {
        List<String> individual = new ArrayList<>();
        Random random = new Random();

        for (String baseGene : baseGenes) {
            // 确保基础基因长度正确
            if (baseGene.length() != GENE_LENGTH) {
                System.out.println("基础基因长度不正确，需要" + GENE_LENGTH + "位，但实际是" + baseGene.length() + "位: " + baseGene);
                baseGene = String.format("%-" + GENE_LENGTH + "s", baseGene).replace(' ', '0');
            }

            // 提取固定部分（前40位）
            String fixedPart = baseGene.substring(0, 40);

            // 解析节数（固定部分第29位：索引29-30）
            int lessonCount = Integer.parseInt(fixedPart.substring(29, 30));

            // === 生成随机时间部分（5位） ===
            int dayOfWeek = random.nextInt(7) + 1; // 周几（1-7）

            // 开始节次（奇数01-19）
            int startSlot;
            do {
                startSlot = 1 + random.nextInt(10) * 2;
            } while (startSlot + lessonCount - 1 > 20);

            // 结束节次
            int endSlot = startSlot + lessonCount - 1;
            String timePart = String.format("%d%02d%02d", dayOfWeek, startSlot, endSlot);

            // === 生成随机教室部分（8位） ===
            int building = random.nextInt(99) + 1;
            int room = random.nextInt(999) + 1;
            int floor = random.nextInt(9) + 1;
            int roomType = random.nextInt(9) + 1;
            String classroomPart = String.format("%02d%03d%d%d", building, room, floor, roomType);

            // 组合完整基因
            String fullGene = fixedPart + timePart + classroomPart;
            // 再次确保完整基因长度正确
            if (fullGene.length() != GENE_LENGTH) {
                fullGene = String.format("%-" + GENE_LENGTH + "s", fullGene).replace(' ', '0');
            }

            individual.add(fullGene);
        }

        return individual;
    }

    /**
     * 根据教师ID查询课程及对应的时间安排列表
     * @param teacherId 教师ID
     * @return 包含课程信息和时间安排的VO列表
     */
    @Override
    public List<CourseAndTimeVo> getCourseAndTimeVoListByTeacherId(String teacherId) {
        System.out.println("查询教师负责的课程列表："+teacherId);
        // 1. 参数校验
        if (teacherId == null || teacherId.trim().isEmpty()) {
            throw new IllegalArgumentException("教师ID不能为空");
        }

        // 2. 查询该教师负责的所有课程
        CourseScheduleDetails queryParam = new CourseScheduleDetails();
        queryParam.setTeacherId(teacherId);
        List<CourseScheduleDetails> courseList = courseScheduleDetailsMapper.selectCourseScheduleDetailsList(queryParam);
        //打印课程列表
        System.out.println("查询教师负责的课程列表："+courseList);

        // 3. 遍历课程，查询每个课程的时间安排并封装VO
        List<CourseAndTimeVo> resultList = new ArrayList<>();
        if (courseList != null && !courseList.isEmpty()) {
            for (CourseScheduleDetails course : courseList) {
                // 创建VO对象
                CourseAndTimeVo courseAndTimeVo = new CourseAndTimeVo();
                // 设置课程基本信息
                courseAndTimeVo.setCourseScheduleDetails(course);

                // 4. 查询当前课程的时间安排（关联class_schedule_detailed表）
                ClassScheduleDetailed timeQuery = new ClassScheduleDetailed();
                timeQuery.setCourseScheduleDetailsId(course.getId()); // 用课程ID关联时间安排
                List<ClassScheduleDetailed> timeList = classScheduleDetailedMapper.selectClassScheduleDetailedList(timeQuery);

                // 设置时间安排列表（即使为空也赋值，避免前端空指针）
                courseAndTimeVo.setClassScheduleDetailedList(timeList);

                // 添加到结果列表
                resultList.add(courseAndTimeVo);
            }
        }

        return resultList;
    }
    //获取培养方案课程详细信息列表
//    @Override
//    public List<CourseScheduleDetails> selectCourseScheduleDetailsListOfCollege(List<String> collegeIds)
//    {
//        return courseScheduleDetailsMapper.selectCourseScheduleDetailsList(courseScheduleDetails);
//    }
    //selectCourseScheduleDetailsByCollegeIds
    @Override
    public List<CourseScheduleDetails> selectCourseScheduleDetailsByCollegeIds(List<String> collegeIds)
    {
        return courseScheduleDetailsMapper.selectCourseScheduleDetailsByCollegeIds(collegeIds);
    }

    /**
     * 根据ID列表查询课程排课详情
     * @param ids ID列表
     * @return 课程排课详情列表
     */
    @Override
    public List<CourseScheduleDetails> selectCourseScheduleDetailsByIds(List<String> ids) {
        List<CourseScheduleDetails> s=courseScheduleDetailsMapper.selectCourseScheduleDetailsByIds(ids);
        System.out.println("根据ID列表查询课程排课详情selectCourseScheduleDetailsByIds service"+s);
        return courseScheduleDetailsMapper.selectCourseScheduleDetailsByIds(ids);
    }

}
